home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / cyber2.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  22KB  |  626 lines

  1.  
  2. /*
  3. AI Code for Invasion Force - an Explore/Conquer Strategic Wargame
  4. Copyright (C) 1996  Brannen Hough
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. /*
  21.    cyber2.c -- artificial intelligence module for Empire II
  22.  
  23. */
  24.  
  25. /* This file contains all the routines associated with AI Type #2.
  26. */
  27.  
  28. #include "global.h"
  29.  
  30.  
  31. /***************************************************************
  32. *************** Production Routines  ***************************
  33. ***************************************************************/
  34.  
  35. void  AI2_set_gov_prod (struct City *metro, struct GovNode *CityOwner)
  36. {
  37.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  38.  
  39.     // Go through the list of Governors.  We find the one governor with
  40.     //  the highest priority request, and start making that request.
  41.  
  42.     // Lets do some error checking
  43.     CityOwner->req.req_gov = -1;
  44.     CityOwner->req.priority = 0;
  45.     CityOwner->req.type = -1;
  46.  
  47.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ) {
  48.       if (Gov->owner == player) {
  49.             AI2_get_gov_req (Gov, metro);  // request gets returned in LastReq
  50.             sprintf(outbuf, "Gov %ld Request - type %s, req_gov %ld, pri %ld",
  51.                 Gov->ID, UnitString[LastReq.type], LastReq.req_gov,
  52.                 LastReq.priority);
  53.             DEBUG_AI (outbuf)
  54.             if( LastReq.priority >= CityOwner->req.priority ) {
  55.                 CityOwner->req.priority = LastReq.priority;
  56.                 CityOwner->req.type = LastReq.type;
  57.                 CityOwner->req.req_gov = LastReq.req_gov;
  58.             }  // End if higher priority
  59.         } // end if my governor
  60.     }  // end for loop
  61.  
  62.     sprintf(outbuf, "Producing a %s for Governor %ld",
  63.         UnitString[CityOwner->req.type], CityOwner->req.req_gov);
  64.     DEBUG_AI(outbuf)
  65.  
  66.     // And we set the city itself to produce this
  67.     if (metro->unit_type != CityOwner->req.type) {  //making a new type
  68.         metro->unit_type = CityOwner->req.type;
  69.         //Tooling up penalty
  70.         metro->unit_wip = -1 * wishbook[metro->unit_type].build/5;
  71.         sprintf (outbuf, "Tooling Up the city to build a %s",
  72.          UnitString[metro->unit_type]);
  73.         DEBUG_AI(outbuf)
  74.     }
  75.     // unit->wip has been set to zero elsewhere.  Don't zero out production
  76.     //  that has already been started when we haven't changed the type.
  77.    //  We have enough handicaps as it is.
  78.  
  79.      return;
  80. }
  81.  
  82.  
  83. void   AI2_get_gov_req (struct GovNode *Gov, struct City *metro)
  84. {
  85.     int     i;
  86.  
  87.     // Mark who has placed this request
  88.     LastReq.req_gov = Gov->ID;
  89.  
  90.     // Set priority based on the mode of the city
  91.     switch( Gov->mode ) {
  92.         case GOV_SEARCH:
  93.             LastReq.priority = 10;
  94.             break;
  95.         case GOV_DEFEND:
  96.             LastReq.priority = 20;
  97.             break;
  98.         default:
  99.             LastReq.priority = 5;
  100.             break;
  101.     }
  102.     if( IsCityTaken(Gov) )  LastReq.priority = 25;
  103.     // Attenuate for distance
  104.     i = AI5_GetDist (metro->col, metro->row, Gov->x, Gov->y);
  105.     LastReq.priority -= i / 2;
  106.     if (LastReq.priority < 1)  LastReq.priority = 1;
  107.  
  108.     if( (Gov->mode == GOV_SEARCH) && (!IsCityTaken(Gov)) ) {
  109.         // The heat is off, let's see what's best to build
  110.         // Make armor units if we can, if not, make infantry.
  111.         LastReq.type = ARMOR;
  112.  
  113.         // Now, change back if we can't make an armor
  114.         if (wishbook[ARMOR].enabled != TRUE) {
  115.             LastReq.type = RIFLE;
  116.         }
  117.         // And, change it back if the area of interest is not good for armor
  118.         if((Gov->hist.TerrainCounts[HEX_PLAINS] +   // Sum total of all the
  119.             Gov->hist.TerrainCounts[HEX_DESERT] +   // terrain armor is very
  120.             //Gov->hist.TerrainCounts[HEX_ARCTIC] +   // fast on
  121.             Gov->hist.TerrainCounts[HEX_BRUSH])
  122.                         <
  123.            (Gov->hist.TerrainCounts[HEX_JUNGLE] +   // Sum total of all the
  124.             Gov->hist.TerrainCounts[HEX_PEAKS] +     //  terrain armor is
  125.             Gov->hist.TerrainCounts[HEX_SWAMP] +    // very slow in.
  126.             Gov->hist.TerrainCounts[HEX_MOUNTAINS]) )
  127.             LastReq.type = RIFLE;
  128.     }
  129.     else {
  130.         // Things are hairy - build infantry until they get better
  131.         LastReq.type = RIFLE;
  132.     }
  133.  
  134.     return;
  135. }
  136.  
  137.  
  138. /* Just a stop gap for now - I have a much better routine to replace
  139.    this one with */
  140. int   AI2_calc_distance (short orgx, short orgy, short destx, short desty)
  141. {
  142.     short   deltx,
  143.             delty;
  144.  
  145.     int     result;
  146.  
  147.    // This seems to work on my graphs - We'll see in
  148.     //   real life - needed some adjustment - still nothing for
  149.    // wrap.  Wrap will need to adjust the deltx and delty I think
  150.    //  Returns the distance in hexes.
  151.    deltx = (destx >= orgx) ? (destx - orgx) : (orgx - destx);
  152.    delty = (desty >= orgy) ? (desty - orgy) : (orgy - desty);
  153.    if (delty == 0)  return (deltx);
  154.    if (deltx == 0)  return (delty);
  155.    // Takes care of the easy cases, now we do 'diagonals'
  156.    result = delty;
  157.    if (orgy % 2) {
  158.       if (destx > orgx) {  result += (deltx - delty / 2); }
  159.       else   result += (deltx - (delty + 1)/2);
  160.    }
  161.    else {
  162.       if (destx > orgx) {  result += (deltx - (delty + 1)/2); }
  163.       else   result += (deltx - delty / 2);
  164.    }
  165.     return  (result);
  166. }
  167.  
  168.  
  169. void  AI2_play_turn( int new_units )
  170. {
  171.     int   MaxLooping = 1000;
  172.     /* Here we may want to look around, give out some orders to units,
  173.        and execute orders to units in a loop until we have done all the
  174.        moves possible for the units.
  175.        */
  176.     AI2_do_all_histograms();
  177.     AI2_give_orders();
  178.     /* We'll add a little failsafe so we don't spend eternity here */
  179.     while( (MaxLooping > 0) && (!DoUnitActions(40,60)) )  MaxLooping--;
  180.     if( MaxLooping <= 0 )
  181.    DEBUG_AI("Exitting AI player's turn - out of actions")
  182.     return;
  183. }
  184.  
  185.  
  186. struct GovNode*  AI2_locate_gov( struct City* metro )
  187. {
  188.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  189.     struct GovNode *NewGov = NULL;
  190.  
  191.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ) {
  192.    if ((Gov->owner == player) &&
  193.        ((Gov->type == GOV_CITY) || (Gov->type == GOV_PORT))
  194.        && (Gov->x == metro->col) && (Gov->y == metro->row)) {
  195.        /* We found the right city governor. */
  196.        return( Gov );
  197.    }  /* End if */
  198.     } /* End for loop */
  199.  
  200.     DEBUG_AI("Couldn't find the governor, making one")
  201.     /* Never found it */
  202.     NewGov = AI1_add_gov( metro );
  203.     /* And, let's set up the governors area of interest */
  204.     AI2_setup_area_of_interest (NewGov);
  205.     return (NewGov);
  206. }
  207.  
  208.  
  209. void  AI2_setup_area_of_interest( struct GovNode* Gov )
  210. {
  211.     /* Set up the immediate area of interest */
  212.     Gov->startx = Gov->x - 2;
  213.     Gov->starty = Gov->y - 2;
  214.     Gov->endx = Gov->x + 2;
  215.     Gov->endy = Gov->y + 2;
  216.     if (!wrap) {
  217.         if (Gov->startx < 0) Gov->startx = 0;
  218.         if (Gov->starty < 0) Gov->starty = 0;
  219.         if (Gov->endx > width - 1) Gov->endx = width - 1;
  220.         if (Gov->endy > height - 1) Gov->endy = height - 1;
  221.     }
  222.     else {
  223.    if (Gov->startx < 0) Gov->startx += width;
  224.    if (Gov->starty < 0) Gov->starty += height;
  225.    if (Gov->endx > width - 1) Gov->endx -= width;
  226.    if (Gov->endy > height - 1) Gov->endy -= height;
  227.     }
  228.     /* Set up the Extended area of interest */
  229.     Gov->Estartx = Gov->x - 5;
  230.     Gov->Estarty = Gov->y - 5;
  231.     Gov->Eendx = Gov->x + 5;
  232.     Gov->Eendy = Gov->y + 5;
  233.     if (!wrap) {
  234.         if (Gov->Estartx < 0) Gov->Estartx = 0;
  235.         if (Gov->Estarty < 0) Gov->Estarty = 0;
  236.         if (Gov->Eendx > width - 1) Gov->Eendx = width - 1;
  237.         if (Gov->Eendy > height - 1) Gov->Eendy = height - 1;
  238.     }
  239.     else {
  240.    if (Gov->Estartx < 0) Gov->Estartx += width;
  241.    if (Gov->Estarty < 0) Gov->Estarty += height;
  242.    if (Gov->Eendx > width - 1) Gov->Eendx -= width;
  243.    if (Gov->Eendy > height - 1) Gov->Eendy -= height;
  244.     }
  245.  
  246.     /* sprintf (outbuf,
  247.        "For Gov %ld, Startx:%ld, Starty:%ld, Endx:%ld, Endy:%ld",
  248.        Gov->ID, Gov->startx, Gov->starty, Gov->endx, Gov->endy);
  249.        DEBUG_AI(outbuf)
  250.        */
  251.     return;
  252. }
  253.  
  254.  
  255. void  AI2_do_all_histograms()
  256. {
  257.     struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
  258.     /* First we update the picture for all the Governors */
  259.     for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ)
  260.    if (Gov->owner == player) {
  261.        AI1_do_one_histogram (Gov);
  262.         AI2_set_gov_mode (Gov);
  263.    }
  264.     /* End for loop */
  265.  
  266. }
  267.  
  268.  
  269. void  AI2_set_gov_mode( struct GovNode* Gov )
  270. {
  271.     enum GovMode new_mode = GOV_SEARCH;
  272.  
  273.     // Now, if we have enemy forces in the area, set to defend
  274.     if( Gov->hist.TotalEUnits > 0 )  new_mode = GOV_DEFEND;
  275.  
  276.     if( new_mode != Gov->mode ) {
  277.         Gov->mode = new_mode;
  278.         // clear all orders
  279.         AI1_clear_all_orders( Gov );
  280.     }
  281.     // And if we lost the city, set the taken flag
  282.     AI1_set_gov_mode( Gov );
  283.  
  284.     return;
  285. }
  286.  
  287.  
  288. void  AI2_give_orders( )
  289. {
  290.     struct  Unit   *unit = (struct Unit *)unit_list.mlh_Head;
  291.     struct GovNode *Gov = NULL;
  292.  
  293.     for (;unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ)
  294.         if ((unit->owner == player) && (unit->move > 0) &&
  295.             (unit->orders == NULL)) {
  296.             /* No orders yet, let's set some
  297.           Ok, we own the unit, and it has moves left, and has a Governor
  298.           owner, and has no standing orders
  299.           Don't just stand there, do something!
  300.           */
  301.            //sprintf(outbuf,
  302.            //"Giving initial orders to unit named %s at %ld,%ld",
  303.             //   unit->name, unit->col, unit->row);
  304.             //   DEBUG_AI(outbuf)
  305.  
  306.             Gov = AI1_FindOwner (unit);
  307.             if (Gov != NULL) {
  308.             if( IsCityTaken( Gov ) ) {
  309.                   /* Have the unit move to the city's location */
  310.                     DEBUG_AI("City Taken! Home Boys!")
  311.                   ComputerGiveOrders (unit, C_ORDER_GOTO, Gov->x,
  312.                      Gov->y, -1, -1, -1);
  313.               } /* End if CityTaken */
  314.               else {
  315.                   if( Gov->mode == GOV_DEFEND ) {
  316.                         DEBUG_AI("Defend mode boys! Repel invaders!")
  317.                      /* We need to get back to help defend the homeland
  318.                          if needed.  Head for the city if far, head for
  319.                          an enemy if close (inside the AOI)
  320.                          */
  321.                      if( (unit->col > Gov->Estartx) &&
  322.                          (unit->col < Gov->Eendx ) &&
  323.                          (unit->row > Gov->Estarty) &&
  324.                          (unit->row < Gov->Eendy) ) {
  325.                             DEBUG_AI("Put 'em on the hunt")
  326.                          ComputerGiveOrders (unit, C_ORDER_HUNT,
  327.                             -1, -1, -1, -1, 6);
  328.                      } /* End of if unit in governors extended zone */
  329.                      else {
  330.                          /* Just head for the city */
  331.                             DEBUG_AI("Too Far! Just head for the city")
  332.                          ComputerGiveOrders (unit, C_ORDER_GOTO,
  333.                             Gov->x, Gov->y, -1, -1, -1);
  334.                      } /* End else not in governors extended range */
  335.                   } /* End if mode = defend */
  336.                   else {
  337.                      /* Have the unit wander randomly */
  338.                         DEBUG_AI("Wander randomly")
  339.                      ComputerGiveOrders (unit, C_ORDER_RANDOM,
  340.                          -1, -1, -1,-1, -1);
  341.                   }
  342.               } /* End else city is not taken */
  343.            } /* End if Gov is not equal to NULl */
  344.             else {
  345.                 /* If we can't find it, just wander randomly */
  346.                 DEBUG_AI("Can't locate owner - wander randomly anyway")
  347.              ComputerGiveOrders (unit, C_ORDER_RANDOM,
  348.                   -1, -1, -1,-1, -1);
  349.             }
  350.        } /* end if owner and has moves left */
  351.     /* End For */
  352. }
  353.  
  354.  
  355. struct MapIcon* AI2_FindClosestEnemyUnit( short orgx, short orgy, int limit )
  356. {
  357.     int  closest = BIG_NUMBER;
  358.     int  i;
  359.     struct MapIcon *closestEnemy = NULL;
  360.     struct MapIcon *icon = (struct MapIcon *) PLAYER.icons.mlh_Head;
  361.  
  362.     for (; icon->inode.mln_Succ; icon = (struct MapIcon *)
  363.       icon->inode.mln_Succ) {
  364.         if (icon->owner != player) {
  365.        i = AI5_GetDist( orgx, orgy, icon->col, icon->row );
  366.        if( (i < limit) && (i < closest) ) {
  367.       closest = i;
  368.       closestEnemy = icon;
  369.        }
  370.    }
  371.     }
  372.     return( closestEnemy );
  373. }
  374.  
  375.  
  376. int  AI2_do_unit_actions()
  377. {
  378.     struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
  379.     struct GovNode *Gov = NULL;
  380.     int         Done = TRUE;
  381.     struct Unit* lastunit = NULL;
  382.     int         times_accessed = 0;
  383.  
  384.     for ( ; unit->unode.mln_Succ; unit = (struct Unit *) unit->unode.mln_Succ)
  385.         if ((unit->owner==player) && (unit->move > 0)) {
  386.        /* Added this last to only give any one unit 10 chances to
  387.           move - if it hasn't by then, skip over it and go to the
  388.           next.  This has the pleasant effect that the unit that
  389.           couldn't move in 10 tries will get another 10 tries to
  390.           move, and so on, until it finally gets skipped for this
  391.           turn. */
  392.      if ( (lastunit != unit) || (times_accessed < 10) )  {
  393.        if( lastunit != unit ) {
  394.           lastunit = unit;
  395.           times_accessed = 0;
  396.        }
  397.        else {
  398.            times_accessed++;
  399.         }
  400.         /* Skip Sentry units */
  401.         if ((unit->orders == NULL) ||
  402.           (unit->orders->reserved != C_ORDER_SENTRY))   continue;
  403.  
  404.        /* Take a look around us and react to enemy units + cities */
  405.        if( AI2_look_around ( unit ) )   return (FALSE);
  406.  
  407.         /* if we have orders, execute them */
  408.         if (unit->orders != NULL) {
  409.             AI2_execute_standing_order(unit);
  410.             return (FALSE);
  411.         }
  412.         else {
  413.             Gov = AI1_FindOwner (unit);
  414.             if (Gov != NULL) {
  415.              DEBUG_AI("No orders, no enemy around. Huh?")
  416.              /* Just skip this unit this turn - the governor will
  417.                  give new orders next turn. */
  418.               unit->move = 0;
  419.               continue;
  420.             } /* End if Gov != NULL */
  421.             else {
  422.               DEBUG_AI("Cannot find unit owner to ad lib turn")
  423.                 DEBUG_AI("For Now, Forget IT!")
  424.                 sprintf (outbuf, "%s Unit %s at %ld,%ld",
  425.                  UnitString[unit->type], unit->name, unit->col,
  426.                   unit->row);
  427.               DEBUG_AI(outbuf)
  428.                 unit->move = 0;
  429.               continue;
  430.             } /* End else Gov == NULL */
  431.        } /* End else figure something out */
  432.      } /* End if the unit is not the same one we accessed 10 times */
  433.      else {
  434.        /* Last unit IS this unit and times accessed >= 10. */
  435.        /* This should ensure that we never get stuck forever - we
  436.           will always finish - removes a potential infinite loop
  437.           when there are TWO enemy planes, over water, that can be
  438.           attacked by ground troops.  They will ping pong between
  439.           them forever. */
  440.        unit->move--;
  441.       }
  442.     } /* End if we own unit and it has moves left */
  443.     /* End for loop */
  444.  
  445.     return (Done);
  446. }
  447.  
  448.  
  449. void AI2_computer_give_orders(struct Unit *unit,int suborder,short destx,
  450.     short desty,short orgx,short orgy,int etc)
  451. {
  452.    struct Order *order=AllocVec((long)sizeof(*order),MEMF_CLEAR);
  453.  
  454.    clear_orders(unit);
  455.    if (order) {
  456.       order->destx = destx;
  457.       order->desty = desty;
  458.       unit->orders = order;
  459.       order->type = ORDER_NONE;
  460.       if (orgx == -1)  order->orgx = unit->col;
  461.       else  order->orgx = orgx;
  462.       if (orgy == -1)  order->orgy = unit->row;
  463.       else  order->orgy = orgy;
  464.       order->processed = FALSE;
  465.       order->etc = etc;
  466.       order->reserved = suborder;       /* using reserved for computer
  467.                                   orders so I don't tread on the human
  468.                                   player's tokens. */
  469.  
  470.       /* This is set up to be in the order they are used most often,
  471.          and set up so that more order types can be added as needed.
  472.     */
  473.       switch (suborder) {
  474.       case C_ORDER_GOTO:
  475.      /* sprintf (outbuf, "%s %s C_ORDER_GOTO from %ld,%ld to %ld,%ld",
  476.         UnitString[unit->type], unit->name, order->orgx,
  477.         order->orgy, order->destx, order->desty);
  478.         DEBUG_AI(outbuf)
  479.         */
  480.      break;
  481.       case C_ORDER_RANDOM:
  482.      /* Standard stuff only */
  483.      break;
  484.       case C_ORDER_HUNT:
  485.      /* Standard stuff only */
  486.      break;
  487.       }
  488.    }
  489. }
  490.  
  491.  
  492. int  AI2_look_around( struct Unit* unit)
  493. {
  494.     int          i, k;
  495.     short        targx, targy;
  496.     struct City* metro;
  497.  
  498.     for (i = 0; i < 6; i++) {
  499.    if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
  500.        if ((metro = city_hereP (targx, targy)) &&
  501.       (metro->owner != player)) {
  502.       /* if there is a city here and we don't own it */
  503.       (void) AI2_locate_gov( metro );
  504.       /* Make a governor for it if there isn't one already */
  505.       /* Then, try to take it */
  506.         if ((unit->type == RIFLE) || (unit->type == ARMOR)
  507.           || (unit->type == AIRCAV)) {
  508.           /* Go for it! */
  509.           /* DEBUG_AI("Jumping enemy city") */
  510.           /* We can check here that we can GET to the city
  511.              and at least tried to take it, bogged down, etc.
  512.              */
  513.           if( move_unit_xy (unit, targx, targy) <= -2) {
  514.              return (1);
  515.           }
  516.           /* Else, look around for something else to attack -
  517.            another city, an enemy unit, etc.
  518.            */
  519.         } /* End if can take city */
  520.        } /* End if city here and it ain't ours! */
  521.    } /* End if hex here */
  522.     } /* End For loop */
  523.     for (i = 0; i < 6; i++) {
  524.    if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
  525.        if (((k = hex_owner(targx,targy)) > 0)&&(k!=player)) {
  526.           /* Somebody there - for now just jump 'em */
  527.           /*DEBUG_AI("Jumping enemy unit") */
  528.           /* Add the if statement so that we keep trying to attack
  529.               an enemy until we succeed or have tried each direction
  530.               once.  There are cases (like an aircraft over water
  531.               attacked by a ground unit) where attacks can't take
  532.               place. */
  533.           if( move_unit_xy (unit, targx, targy) <= -2 ) {
  534.               /* We successfully attacked, ran out of gas, couldn't
  535.                   move, etc. */
  536.               return (1);
  537.           }
  538.           /* Else, try a different enemy unit */
  539.        }  /* End if bad guy here */
  540.    } /* End if hex here */
  541.     } /* End for loop */
  542.     return (0);
  543. }
  544.  
  545.  
  546. void  AI2_execute_standing_order( struct Unit* unit )
  547. {
  548.     int     result;
  549.  
  550.     if ((unit->orders == NULL) || (unit->orders->type != ORDER_NONE)) {
  551.    DEBUG_AI("Big problem in execute_standing_order - no orders!")
  552.    sprintf (outbuf, "%s %s has no standing orders to execute - aborting",
  553.        UnitString[unit->type], unit->name);
  554.    DEBUG_AI(outbuf)
  555.    return;
  556.     }
  557.  
  558.     switch (unit->orders->reserved) {
  559.         case  C_ORDER_GOTO:
  560.             result = AI1_command_headto(unit);
  561.             if (result < 0) clear_orders(unit);   /* problem */
  562.             if (result == 0) clear_orders(unit);  /* done */
  563.             break;
  564.         case  C_ORDER_RANDOM:
  565.        /* Let's break the mold and use a more advanced AI routine */
  566.             AI3_command_random(unit);
  567.             break;
  568.         case  C_ORDER_HUNT:
  569.           result = AI2_command_hunt(unit);
  570.            if (result < 0) clear_orders(unit);  /* wouldn't work */
  571.            break;
  572.         default:
  573.             DEBUG_AI("Unknown command type found in execute_standing_order!")
  574.             break;
  575.     }
  576.     return;
  577. }
  578.  
  579.  
  580. int   AI2_command_hunt( struct Unit* unit )
  581. {
  582.     int i, j;
  583.     int result;
  584.     /* We find the closest enemy unit to us and move towards it */
  585.     struct MapIcon *icon = AI2_FindClosestEnemyUnit( unit->col, unit->row, 6 );
  586.  
  587.     if( icon ) {
  588.       /* We see one! Move towards him */
  589.        /* Select the correct direction to look in */
  590.       i = 0;
  591.        if (icon->col - unit->col <= 0)  i = 3;
  592.       if( (icon->col == unit->col) && (unit->col%2 == 0) ) i = 0;
  593.        if (icon->row - unit->row < 0)  i += 1;
  594.       if (icon->row == unit->row)     i += 2;
  595.  
  596.        /* Let's move in the three most likely directions only */
  597.       for (j = 0; j < 3; j++) {
  598.            /* -1 is the only return value where a move might still be possible
  599.               We must be sure we only do ONE move - ever */
  600.             result = move_unit_dir( unit, DirArray[i][j] );
  601.           if( result != -1 )  {
  602.              /*sprintf (outbuf, "Moved %s, result %ld",
  603.                DirString[DirArray[i][j]], result);
  604.               DEBUG_AI(outbuf)
  605.               */
  606.              return (0);  /* Made a move */
  607.           }
  608.            else {
  609.                 // Could not move in that direction - try another
  610.              sprintf (outbuf,
  611.                  "%s %s Tried to move in direction %s, result %ld",
  612.                    UnitString[unit->type], unit->name,
  613.                   DirString[DirArray[i][j]], result);
  614.                DEBUG_AI(outbuf)
  615.           }
  616.       } /* End for loop */
  617.  
  618.         // All three directions did not pan out
  619.        return -1;
  620.     }
  621.     // else
  622.     return -1;  /* No one nearby to chase */
  623. }
  624.  
  625.  
  626.